#pragma once

#include <iostream>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <string>
#include <clocale>
#include <algorithm>
#include <iterator>
#include <exception>

using namespace std;

struct node
{
	int value;
	node *next;

	node()
	{
		value = 0;
		next = nullptr;
	}

	node(int i)
	{
		value = i;
		next = nullptr;
	}
};


class my_stack
{

private:
	node *start = nullptr;
	node *tos = nullptr;
	int capacity_ = 10;

	void create_nodes(){
		start = new node;
		tos = start;
		for (auto i = 1; i < this->capacity_; i++)
		{
			node *n = new node;
			tos->next = n;
			tos = n;
		}
		tos = nullptr;
	}

	void clear(){
		node *tmp = start;
		while (tmp != nullptr){
			start = tmp->next;
			delete tmp;
			tmp = start;
		}
		tos = nullptr;
	}


public:

	my_stack()
	{
		create_nodes();
	}

	my_stack(int size)
	{
		if (size < 1){
			throw exception("Exception: the stack must have a size of 1 or more.");
		}
		this->capacity_ = size;
		create_nodes();
	}

	~my_stack()
	{
		clear();
	}


	int capacity(){
		return this->capacity_;
	}

	void push(int i){
		if (tos == start){
			throw exception("Exception: the stack is full.");
		}
		node *tmp = start;
		node *prev = start;
		while (tmp != tos){
			prev = tmp;
			tmp = tmp->next;
		}
		tos = prev;
		tos->value = i;
	}

	int top(){
		return tos->value;
	}

	void pop(){
		if (tos == nullptr){
			throw exception("Exception: the stack is empty.");
		}
		tos = tos->next;
	}

	int size(){
		int size = 0;
		node *tmp = tos;
		while (tmp != nullptr){
			tmp = tmp->next;
			size++;
		}
		return size;
	}

	my_stack& my_stack::operator=(const my_stack &v)
	{
		if (this == &v)
			return *this;
		else
		{
			clear();

			start = new node(v.start->value);
			tos = start;

			node *tmp1 = v.start;
			node *tmp2 = start;

			while (tmp1->next != nullptr){
				tmp2->next = new node(tmp1->next->value);
				tmp1 = tmp1->next;
				tmp2 = tmp2->next;
				if (v.tos == tmp1){	tos = tmp2; }
			}
			return *this;
		}	
	}

	my_stack(const my_stack &v)
	{
		start = new node(v.start->value);
		tos = start;

		node *tmp1 = v.start;
		node *tmp2 = start;

		while (tmp1->next != nullptr){
			tmp2->next = new node(tmp1->next->value);
			tmp1 = tmp1->next;
			tmp2 = tmp2->next;
			if (v.tos == tmp1){ tos = tmp2; }
		}
	}

	class iterator
	{
	public:
		typedef iterator self_type;
		typedef node  value_type;
		typedef node& reference;
		typedef node* pointer;
		typedef std::forward_iterator_tag iterator_category;
		typedef int difference_type;

		iterator(pointer ptr) : ptr_(ptr) { } //Constructor
		self_type operator++()
		{
			self_type i = *this;
			ptr_ = ptr_->next;
			return i;
		}
		self_type operator++(int junk) { ptr_ = ptr_->next; return *this; }
		reference operator*() { return *ptr_; }
		pointer operator->() { return ptr_; }
		bool operator==(const self_type& rhs) { return ptr_ == rhs.ptr_; }
		bool operator!=(const self_type& rhs) { return ptr_ != rhs.ptr_; }

	private:
		pointer ptr_;
	};

	iterator begin() { return iterator(tos); }
	iterator end() { return iterator(nullptr); }



};


